package com.miyake.dsp.osa;

import com.miyake.dsp.ComplexArray;
import com.miyake.dsp.ScilabExecute;
import com.miyake.dsp.analyzer.PeakSearch;
import com.miyake.dsp.analyzer.PeakSearchSetting;
import com.miyake.dsp.common.UnitConverter;
import com.miyake.dsp.convolution.ConvolutionImplScilab;
import com.miyake.dsp.convolution.ConvolutionSetting;
import com.miyake.dsp.ui.LineChartPanel;

public class WdmGenerator {
	
	private double[] source;
	private double span;

	private int peakIndex;
	private boolean gainFlat;
	private double gainValue;
	private boolean aseFlat;
	private double aseValue;
	private boolean gainEnabled;
	private boolean aseEnabled;
	private boolean whiteNoiseEnabled;
	private double whiteNoiseValue;
	
	
	public WdmGenerator(double[] in, double span) {
		this.source = in;
		this.span = span;
		PeakSearch peakSearch = new PeakSearch(new PeakSearchSetting(10, 10));
		peakSearch.setSource(new ComplexArray(in));
		peakIndex = peakSearch.getPeakIndex();
	}
	
	public WdmGenerator(double[] in, double span, int peakIndex) {
		this.source = in;
		this.span = span;
		this.peakIndex = peakIndex;
	}

	
	public boolean isWhiteNoiseEnabled() {
		return whiteNoiseEnabled;
	}

	public void setWhiteNoiseEnabled(boolean whiteNoiseEnabled) {
		this.whiteNoiseEnabled = whiteNoiseEnabled;
	}

	public double getWhiteNoiseValue() {
		return whiteNoiseValue;
	}

	public void setWhiteNoiseValue(double whiteNoiseValue) {
		this.whiteNoiseValue = whiteNoiseValue;
	}

	public boolean isGainFlat() {
		return gainFlat;
	}

	public void setGainFlat(boolean gainFlat) {
		this.gainFlat = gainFlat;
	}

	public double getGainValue() {
		return gainValue;
	}

	public void setGainValue(double gainValue) {
		this.gainValue = gainValue;
	}

	public boolean isAseFlat() {
		return aseFlat;
	}

	public void setAseFlat(boolean aseFlat) {
		this.aseFlat = aseFlat;
	}

	public double getAseValue() {
		return aseValue;
	}

	public void setAseValue(double aseValue) {
		this.aseValue = aseValue;
	}

	public boolean isGainEnabled() {
		return gainEnabled;
	}

	public void setGainEnabled(boolean gainEnabled) {
		this.gainEnabled = gainEnabled;
	}

	public boolean isAseEnabled() {
		return aseEnabled;
	}

	public void setAseEnabled(boolean aseEnabled) {
		this.aseEnabled = aseEnabled;
	}

	public void setGain(boolean flat, double value) {
		gainEnabled = true;
		gainFlat = flat;
		gainValue = value;
	}
	
	public void setAse(boolean flat, double value) {
		aseEnabled = true;
		aseFlat = flat;
		aseValue = value;
	}
	
	
	private double getStep() {
		double step = this.span / (this.source.length - 1);
		return step;
	}

	public double[] getWdm(int points, double spacing, int peaks) {

		int spacingPoint = (int)(spacing * (double)source.length / span);
		int mask = 0;//(points / spacingPoint - peaks) / 2;
		double[] impulse = new double[points];
		int peak = 0;
		boolean b = false;
		
		int xoffset = 1;
		
		for (int i = xoffset; i < impulse.length; i++) {

			if (i % spacingPoint == 0) {
				peak++;
				b = true;
			}
			else {
				impulse[i] = 0;
			}
			if (peak > mask && peak < (points / spacingPoint) - mask && b) {
				impulse[i] = 1;
				b = false;
			}
		}
		double[] ret = ScilabExecute.execute("y=convol(data1, data2);", new ComplexArray(source), new ComplexArray(impulse), "y").getRealPart();

	
		double[] ret2 = new double[points];
		for (int i = 0; i < points; i++) {
			ret2[i] = ret[i + (ret.length - ret2.length)/ 2];
		}

		ret2 = getEffect(ret2);
		return ret2;
		//return addASE(addGain(ret));
	}

	private double[] getEffect(double[] ret2) {
		if (isWhiteNoiseEnabled()) {
			ret2 = addWhiteNoise(ret2);
		}
		
		//return ret;
		if (isGainEnabled()) {
			ret2 = addGain(ret2);
		}

		if (isAseEnabled()) {
			ret2 = addASE(ret2);
		}
		return ret2;
	}

	private double[] addGain(double[] in) {
		double f = Math.PI / in.length;
		double[] ret = new double[in.length];
		for (int i = 0; i < ret.length; i++) {
			if (isGainFlat()) {
				ret[i] = in[i] * Math.pow(10.0, gainValue/10.0);
			}
			else {
				ret[i] = in[i] * (1 + Math.sin(i * f))/2.0 * Math.pow(10.0, gainValue/10.0);
			}
		}
		return ret;
	}

	private double[] addASE(double[] in) {
		double f = Math.PI / in.length;
		double[] ret = new double[in.length];
		for (int i = 0; i < ret.length; i++) {
			if (isAseFlat()) {
				ret[i] = in[i] + aseValue * 1e-6;
			}
			else {
				ret[i] = in[i] + (Math.sin(i * f) + 1) / 2.0 * aseValue * 1e-6;
			}
		}
		return ret;
	}

	private double[] addWhiteNoise(double[] in) {
		double[] ret = new double[in.length];
		for (int i = 0; i < ret.length; i++) {
			ret[i] = in[i] + Math.random() * whiteNoiseValue * 1e-6;
		}
		return ret;	
	}
	
	public int getPeakIndex() {
		return peakIndex;
	}

	public void setPeakIndex(int peakIndex) {
		this.peakIndex = peakIndex;
	}
	
}
